35장. 경로 · 호스트 기반 라우팅으로 서비스 쪼개기
이 장에서 말하고자 하는 것
앞 장에서 우리는 ALB의 부품 — 리스너 · 규칙 · 타깃 그룹 — 을 봤다.
이 장은 그 부품을 가지고
하나의 ALB로 여러 마이크로서비스를 어떻게 나눠 받는가
를 본다.
마이크로서비스 구조에서 ALB가 가장 빛나는 지점이다.
1. 출발 — 모놀리스에서 MSA로
작은 서비스에는 보통 ALB 한 대 + 서버 한 묶음이면 충분하다.
사용자 → ALB → web 서버 (모놀리스)
서비스가 커지면 기능별로 나누고 싶어진다.
주문, 사용자, 결제, 알림 ...
각각을 다른 서비스로 띄우면
사용자 → ALB → orders 서비스
users 서비스
payments 서비스
이때 ALB가 어떻게 분기할지 결정해야 한다.
2. 두 가지 분기 방법
ALB가 서비스를 나누는 방법은 크게 두 가지다.
- 경로 기반(Path-based)
- 호스트 기반(Host-based)
둘은 함께 써도 된다.
3. 경로 기반 라우팅
같은 도메인 안에서 경로로 서비스를 나눈다.
api.example.com/orders/* → orders 서비스
api.example.com/users/* → users 서비스
api.example.com/payments/* → payments 서비스
api.example.com/* → web (기본)
특징:
- 클라이언트는 도메인 하나만 알면 된다
- 인증서도 한 장이면 된다
- 프론트엔드와 같은 도메인이라 CORS가 단순해진다
작은 ~ 중간 규모 MSA에 적합하다.
4. 호스트 기반 라우팅
서브도메인으로 나눈다.
orders.example.com → orders 서비스
users.example.com → users 서비스
payments.example.com → payments 서비스
admin.example.com → admin 서비스
특징:
- 서비스 경계가 명확하다
- DNS 와 인증서 관리 부담이 늘어난다 (ACM 와일드카드로 완화 가능)
- 보안 경계 분리에 유리하다
내부망과 외부망이 섞인 환경이나
관리자/사용자 영역 분리에 자주 쓴다.
5. 둘을 함께 쓰는 패턴
운영에서는 보통 섞어 쓴다.
api.example.com/orders/* → orders
api.example.com/users/* → users
api.example.com/payments/* → payments
admin.example.com/* → admin
외부 사용자용 API는 경로로 나누고
관리자나 별도 도메인이 필요한 영역은 호스트로 분리
6. 규칙은 우선순위대로
ALB의 규칙은 우선순위(priority)대로 평가된다.
priority 10 : path = /api/orders/* → TG-orders
priority 20 : path = /api/users/* → TG-users
priority 30 : path = /api/payments/* → TG-payments
default : * → TG-web
priority가 작을수록 먼저 평가된다.
가장 구체적인 규칙을 앞에 둔다.
/api/orders/special ← 먼저
/api/orders/* ← 그다음
/api/* ← 그 다음
/* ← 마지막
7. 서비스마다 타깃 그룹은 따로
이게 가장 중요한 원칙이다.
orders → TG-orders → orders 서비스
users → TG-users → users 서비스
payments → TG-payments → payments 서비스
한 ALB · 여러 타깃 그룹 · 각 타깃 그룹은 한 서비스
이렇게 분리해야
- 서비스별 헬스 체크가 독립된다
- 서비스별 스케일링이 분리된다
- 서비스별 배포가 분리된다
- 한 서비스 장애가 다른 서비스에 안 번진다
8. 우리 서비스에서
척추에 점을 찍어보자.
[사용자]
↓ DNS
[CloudFront]
↓
[API Gateway]
↓
[ALB] ← 여기서 경로로 4개로 나뉜다
├─ /api/orders/* → ECS "orders"
├─ /api/users/* → ECS "users"
├─ /api/payments/* → ECS "payments"
└─ /* → ECS "web"
이 ALB가 사실상
사용자가 만든 요청을 마이크로서비스로 흩어 보내는 분배기
역할을 한다.
9. 직접 확인해보기 — CLI
규칙 추가
aws elbv2 create-rule \
--listener-arn <listener-arn> \
--priority 10 \
--conditions Field=path-pattern,Values='/api/orders/*' \
--actions Type=forward,TargetGroupArn=<tg-orders-arn>
규칙 우선순위 변경
aws elbv2 set-rule-priorities \
--rule-priorities RuleArn=<rule-arn>,Priority=5
어떤 규칙에 매칭됐는지 확인
ALB 액세스 로그를 S3에 켜두면
요청별로 어떤 타깃 그룹에 갔는지 다 남는다.
target_group_arn = arn:aws:elasticloadbalancing:.../TG-orders/...
10. 코드로는 이렇게 생겼다 — Terraform
서비스 3개를 한 ALB로 분기하는 모양이다.
# 공통 ALB와 리스너는 앞 장에 있다고 가정
locals {
services = {
orders = { path = "/api/orders/*", port = 8081 }
users = { path = "/api/users/*", port = 8082 }
payments = { path = "/api/payments/*", port = 8083 }
}
}
resource "aws_lb_target_group" "svc" {
for_each = local.services
name = "tg-${each.key}"
port = each.value.port
protocol = "HTTP"
target_type = "ip"
vpc_id = aws_vpc.main.id
health_check {
path = "/health"
}
}
resource "aws_lb_listener_rule" "svc" {
for_each = local.services
listener_arn = aws_lb_listener.https.arn
priority = 100 + index(keys(local.services), each.key)
condition {
path_pattern {
values = [each.value.path]
}
}
action {
type = "forward"
target_group_arn = aws_lb_target_group.svc[each.key].arn
}
}
서비스를 추가할 때 services 맵에 한 줄만 더하면 된다.
11. 이렇게 쓰면 망한다 — 안티패턴
안티패턴 1. 정규식 같은 복잡한 매칭을 ALB에 떠넘긴다
ALB의 path_pattern은 *, ? 정도만 지원한다.
복잡한 라우팅을 ALB에 넣으면 빠르게 한계가 온다.
복잡한 매칭은 애플리케이션 또는 API Gateway로
안티패턴 2. 같은 path를 여러 priority에 중복으로 둔다
priority 10 : /api/* → TG-monolith
priority 20 : /api/v2/* → TG-v2
10이 먼저 잡아서 20은 영원히 실행되지 않는다.
더 구체적인 규칙을 작은 priority에 둔다
안티패턴 3. 서비스를 늘릴 때마다 ALB를 새로 만든다
ALB 자체가 비용이 든다.
한 ALB에 규칙 100개까지는 무리 없이 들어간다.
한 ALB로 모으되, 너무 많아지면 도메인 단위로 나눈다
안티패턴 4. 모든 서비스를 한 타깃 그룹에 묶고 path만 다르게 둔다
타깃 그룹은 “같은 역할의 서버 묶음” 이다.
역할이 다른 서비스를 같은 TG에 두면
- 헬스 체크가 의미를 잃고
- 스케일링이 묶이고
- 장애가 서로 번진다
12. 한 줄로 정리
하나의 ALB에서 경로와 호스트로 트래픽을 나눠
각 마이크로서비스의 타깃 그룹으로 보내는 것이 MSA의 진입 구조다
13. 이 장의 핵심 정리
- 경로 기반과 호스트 기반은 ALB에서 서비스를 나누는 두 축이다.
- 두 방식은 함께 써도 된다.
- 서비스마다 타깃 그룹을 반드시 따로 둔다.
- priority는 가장 구체적인 규칙을 앞에 둔다.
- 한 ALB로 수십 개 서비스까지는 충분히 운영된다.
- 복잡한 라우팅은 ALB가 아니라 API Gateway / 애플리케이션 단계로 옮긴다.